#include "FilelistQueryService.h"
#include "FilelistQuery.pb.h"
#include "CryptoUtil.h"

#include <signal.h>
#include <nlohmann/json.hpp>
#include <workflow/WFFacilities.h>
#include <workflow/MySQLResult.h>
#include <workflow/WFTaskFactory.h>
#include <string>
#include <vector>

using namespace srpc;
using namespace protocol;
using std::string;
using std::vector;


namespace
{

	using json = nlohmann::json;

	WFFacilities::WaitGroup wait_group(1);

	//默认的注册服务器的端口
	constexpr const unsigned short DEFAULT_QUERY_PORT = 1237;
	//默认的注册服务器的ip
	constexpr const char* DEFAULT_QUERY_IP = "127.0.0.1";
	//mysql的url
	constexpr const char* MYSQL_URL = "mysql://root:123@127.0.0.1/CloudDisk2";
	//最大重试次数
	constexpr const int RE_TRY_MAX = 3;

	void sig_handler(int signo)
	{
		wait_group.done();
	}


	/* ************************************************************************************ */
	/* *******************************获取文件列表****************************************** */
	/* ************************************************************************************ */

	void handleFilelistQuery(::l::FilelistQueryResponse* response, WFMySQLTask* task) {

		// 任务失败: 及早失败原则
		if (task->get_state() != WFT_STATE_SUCCESS) {
			response->set_statuscode(500);
#ifdef BUG
			std::cerr << "Error: " << WFGlobal::get_error_string(task->get_state(), task->get_error());
#endif
			return;
		}

		MySQLResponse* resp = task->get_resp();
		MySQLResultCursor cursor{ resp };

		if (cursor.get_cursor_status() != MYSQL_STATUS_GET_RESULT) {

			response->set_statuscode(500);
#ifdef BUG
			std::cout << "mysql failed to select created_at" << "\n";
#endif
			return;
		}

		vector<MySQLCell> record{};
		json filelist{};

		for (int i = 0; cursor.fetch_row(record); i++) {

			string filename{ record[0].as_string() };
			string hashcode{ record[1].as_string() };
			string size{ std::to_string(record[2].as_ulonglong()) };
			string created_at{ record[3].as_datetime() };
			string last_update{ record[4].as_datetime() };

			filelist[i] = json{ {"FileHash", std::move(hashcode)},
							{"FileName",std::move(filename)},
							{"FileSize", std::move(size)},
							{"UploadAt", std::move(created_at)},
							{"LastUpdated", std::move(last_update)} };

		}
		response->set_statuscode(200);
		response->set_filelist(filelist.dump());

#ifdef BUG
		std::cout << "json:\n " << filelist.dump(2) << "\n";
#endif

	}

}//end of anonymous namaspace


class FilelistQueryServiceImpl : public ::l::FilelistQuery::Service
{
public:

	void FilelistQuery(::l::FilelistQueryRequest* request, ::l::FilelistQueryResponse* response, srpc::RPCContext* ctx) override
	{

		//获取username和limit
		string username{ request->username() };
		string limit{ request->limit() };

		string url{ MYSQL_URL };
		string sql{ "SELECT  users_files.filename,files.filehash, files.size, users_files.created_at, users_files.last_update"
					" FROM users JOIN users_files ON users.id = users_files.uid "
					"JOIN files on files.id = users_files.fid "
					"WHERE users_files.status = 0 AND users.username = \"" };
		sql.append(username).append("\" AND users.tomb = 0 LIMIT ").append(limit);
#ifdef BUG
		std::cout << "query sql: " << sql << "\n";
#endif

		WFMySQLTask* task = WFTaskFactory::create_mysql_task(MYSQL_URL, RE_TRY_MAX, std::bind(handleFilelistQuery, response, std::placeholders::_1));

		task->get_req()->set_query(sql);

		SeriesWork* series = ctx->get_series();
		series->push_back(task);

	}
};

int main()
{
	signal(SIGINT, sig_handler);

	SRPCServer server;

	FilelistQueryServiceImpl filelist_query_impl;
	server.add_service(&filelist_query_impl);

	if (server.start(DEFAULT_QUERY_PORT) == 0) {
		wait_group.wait();
		server.stop();
	}
	else {
#ifdef BUG
		std::cout << "filelist_query server start failed\n";
#endif
	}
	google::protobuf::ShutdownProtobufLibrary();
	return 0;
}
